/* 纹理 */
class Texture2D{
	constructor(gl, data, size={}, opt={}){
		const {width=1, height=1} = size;
		const {
			bindPoint=gl.TEXTURE_2D, //绑定点
			mimapLevel=0, //mimap等级
			internalFormat=gl.RGBA, //内部格式
			format=gl.RGBA, //格式
			dataType=gl.UNSIGNED_BYTE, //传入数据类型
			reduce, //缩小 gl.NEAREST
			enlarge=gl.NEAREST, //放大
			wrapX, //X重复 gl.CLAMP_TO_EDGE
			wrapY, //Y重复 gl.CLAMP_TO_EDGE
			generateMipmap=false
		} = opt;
		this.gl = gl;
		this.data = data;
		this.size = size;
		this.bindPoint = bindPoint;
		this.mimapLevel = mimapLevel;
		this.internalFormat = internalFormat;
		this.format = format;
		this.dataType = dataType;
		this.reduce = reduce;
		this.enlarge = enlarge;
		this.wrapX = wrapX;
		this.wrapY = wrapY;
		
		//创建纹理
		const texture = gl.createTexture();
		this.texture = texture;
		gl.bindTexture(bindPoint, texture);
		gl.texImage2D(
			bindPoint,
			mimapLevel,
			internalFormat,
			width,
			height,
			0, //border
			format,
			dataType,
			data
		);
		
		if (reduce) //纹理需要被缩小
			gl.texParameteri(bindPoint, gl.TEXTURE_MIN_FILTER, reduce);
		if (enlarge) //纹理需要被放大
			gl.texParameteri(bindPoint, gl.TEXTURE_MAG_FILTER, enlarge);
		if (wrapX)//纹理坐标超出了s坐标的边界
			gl.texParameteri(bindPoint, gl.TEXTURE_WRAP_S, wrapX);
		if (wrapY)//纹理坐标超出了t坐标的边界
			gl.texParameteri(bindPoint, gl.TEXTURE_WRAP_T, wrapY);
		
		if (generateMipmap)
			gl.generateMipmap(bindPoint);
	}
	
	update(){
		this.gl.bindTexture(this.bindPoint, this.texture);
		this.gl.texImage2D(
			this.bindPoint,
			this.mimapLevel,
			this.internalFormat,
			this.size.width,
			this.size.height,
			0, //border
			this.format,
			this.dataType,
			this.data
		);
		return this;
	}
	
	//生成Mimap
	generateMimap(){
		this.bind(this.gl.TEXTURE_2D, undefined, ()=>{
			this.gl.generateMipmap(this.gl.TEXTURE_2D);
		});
		return this;
	}
	
	//绑定
	bind(bindPoint=this.gl.TEXTURE_2D, unit=this.gl.getParameter(this.gl.ACTIVE_TEXTURE)){
		this.gl.activeTexture(this.gl.TEXTURE0 + unit);
		this.gl.bindTexture(bindPoint, this.texture);
		return this;
	}
	
	//安全绑定
	bindSafe(bindPoint=this.gl.TEXTURE_2D, unit=this.gl.getParameter(this.gl.ACTIVE_TEXTURE), func){
		//参数默认值
		if (func == undefined){
			func = unit;
			unit=this.gl.getParameter(this.gl.ACTIVE_TEXTURE);
		}
		//保存状态
		const activatingTexture = this.gl.getParameter(this.gl.ACTIVE_TEXTURE);
		let bindingTexture;
		switch (bindPoint){
			case this.gl.TEXTURE_2D:
				bindingTexture = this.gl.getParameter(this.gl.TEXTURE_BINDING_2D);
				break;
			default:
				throw "[Texture2D] Unknown bindPoint:" + bindPoint;
		}
		//改变状态
		if (activatingTexture != this.gl.TEXTURE0 + unit)
			this.gl.activeTexture(this.gl.TEXTURE0 + unit);
		this.gl.bindTexture(bindPoint, this.texture);
		func();
		//恢复状态
		if (activatingTexture != this.gl.TEXTURE0 + unit)
			this.gl.activeTexture(activatingTexture);
		this.gl.bindTexture(bindPoint, bindingTexture);
		return this;
	}
	
	
	static switchUnit(gl, unit=0){
		gl.activeTexture(gl.TEXTURE0 + unit);
	}
}
